﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

/// <summary>
/// 为所有动态模块构建器提供抽象基类。
/// </summary>
public abstract class MemberBuilder : SingleLinkedListNode {

    #region 节点

    /// <summary>
    /// 用于标记成员类型和其它属性。
    /// </summary>
    /// <remarks>
    /// 此类型和 Modifier 有一定关系。
    /// </remarks>
    public enum MemberAttributes {

        #region 公共成员属性

        /// <summary>
        /// 标记当前成员是一个实例成员。
        /// </summary>
        @instance = 0,

        /// <summary>
        /// 表示静态的成员。
        /// </summary>
        @static = 1 << 0,

        /// <summary>
        /// 表示只读的成员。
        /// </summary>
        @readonly = 1 << 1,

        /// <summary>
        /// 表示必需的成员。
        /// </summary>
        @required = 1 << 2,

        /// <summary>
        /// 表示常量成员。
        /// </summary>
        @const = 1 << 3,

        /// <summary>
        /// 表示最终的成员。标记当前类不可被继承、函数不可被重写、字段不可被改变。
        /// </summary>
        final = 1 << 4,

        /// <summary>
        /// 表示覆盖的成员。
        /// </summary>
        @new = 1 << 5,

        /// <summary>
        /// 表示抽象的成员。
        /// </summary>
        @abstract = 1 << 6,

        /// <summary>
        /// 表示虚成员。
        /// </summary>
        @virtual = 1 << 7,

        /// <summary>
        /// 表示重写的成员。
        /// </summary>
        @override = 1 << 8,

        /// <summary>
        /// 表示外部的成员。
        /// </summary>
        @extern = 1 << 9,

        /// <summary>
        /// 表示不定的成员。
        /// </summary>
        @volatile = 1 << 10,

        #endregion

        #region 成员访问权限

        @public = 0 << 11,

        protectedOrInternal = 1 << 11,

        protectedAndInternal = 2 << 11,

        @protected = 3 << 11,

        @internal = 4 << 11,

        @private = 5 << 11,

        privateScope = 6 << 11,

        compilerGenerated = 7 << 11,

        ACCESS = @public | protectedOrInternal | protectedAndInternal | @protected | @internal | @private | privateScope | compilerGenerated,

        #endregion

        #region 成员公用标记

        /// <summary>
        /// 标记当前成员拥有注解。
        /// </summary>
        hasAnnotations = 1 << 16,

        /// <summary>
        /// 标记当前成员拥有自定义属性。
        /// </summary>
        hasCustomAttributes = 1 << 17,

        /// <summary>
        /// 标记当前成员拥有文档。
        /// </summary>
        hasDoc = 1 << 18,

        /// <summary>
        /// 标记当前名字由 Unicode 字符组成。
        /// </summary>
        unicodeName = 1 << 19,

        /// <summary>
        /// 标记当前成员名是链接外部的字符串。
        /// </summary>
        linkedName = 1 << 20,

        /// <summary>
        /// 标记当前成员拥有源位置。
        /// </summary>
        hasSourceLine = 1 << 21,

        #endregion

        #region 成员私有标记

        /// <summary>
        /// 当前类已显示声明布局。
        /// </summary>
        explicitLayout = 1 << 22,

        /// <summary>
        /// 当前类含有静态字段。
        /// </summary>
        hasStaticField = 1 << 23,

        /// <summary>
        /// 当前方法或属性含有显示声明的接口。
        /// </summary>
        hasImplementedType = 1 << 23,

        #endregion

        #region 成员类型

        @namespace = 0 << 24,

        @class = 1 << 24,

        @struct = 2 << 24,

        @enum = 3 << 24,

        @interface = 4 << 24,

        method = 5 << 24,

        property = 6 << 24,

        field = 7 << 24,

        MEMBER = @namespace | @class | @struct | @enum | @interface | method | property | field,
        empty,

        #endregion

    }

    /// <summary>
    /// 获取或设置当前成员的属性。
    /// </summary>
    public MemberAttributes attributes;

    /// <summary>
    /// 表示一个注解。
    /// </summary>
    public sealed class Annotation : SingleLinkedListNode {

        public MethodBuilder type;

        public ByteArrayList data;

    }
    
    /// <summary>
    /// 获取当前成员的所有注解。
    /// </summary>
    public SingleLinkedList<Annotation> annotations = new SingleLinkedList<Annotation>();

    /// <summary>
    /// 获取或设置当前成员的自定义属性。
    /// </summary>
    public ByteArrayList customAttributes;

    /// <summary>
    /// 获取或设置当前成员的文档部分。
    /// </summary>
    public string doc;

    /// <summary>
    /// 获取或设置当前成员的名字。
    /// </summary>
    public string name;

    /// <summary>
    /// 获取或设置当前成员的位置。
    /// </summary>
    public Checkpoint location;

    #endregion

    #region 写入

    /// <summary>
    /// 当前成员的序号。
    /// </summary>
    public uint id;

    /// <summary>
    /// 当前成员在目标文件中存储的偏移。
    /// </summary>
    public uint offset;

    /// <summary>
    /// 用于保存数据时存储相关的数据。
    /// </summary>
    public class WriteContext {

        /// <summary>
        /// 获取当前保存的目标流。
        /// </summary>
        public Stream target;

        Dictionary<string, uint> _stringMaps = new Dictionary<string, uint>(128);

        /// <summary>
        /// 获取字符串存储形式的偏移数。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public uint getStringOffset(string value) {
            uint offset;
            _stringMaps.TryGetValue(value, out offset);
            return offset;
        }

        public void setStringOffset(string name, uint id) {
            _stringMaps.Add(name, id);
        }

        /// <summary>
        /// 获取或设置当前的上级成员。
        /// </summary>
        public MemberBuilder parentMember;

        /// <summary>
        /// 当前分配的成员 ID 。
        /// </summary>
        public uint currentId;

        /// <summary>
        /// 依赖模块列表存储在当前文件的偏移位置。
        /// </summary>
        public uint requiredModuleIndexOffset;

        /// <summary>
        /// 检查点列表存储在当前文件的偏移位置。
        /// </summary>
        public uint checkPointIndexOffset;

        /// <summary>
        /// 成员信息表存储在当前文件的偏移位置。
        /// </summary>
        public uint memberIndexOffset;

        public void writeByteArrayList(ByteArrayList list) {
            writeInt((uint)list.length);
            list.write(target);
        }

        public void writeInt(uint data) {
            target.WriteByte((byte)(data >> 24));
            target.WriteByte((byte)(data >> 16));
            target.WriteByte((byte)(data >> 8));
            target.WriteByte((byte)data);
        }

        public void writeVersion(Version data) {
            target.WriteByte(data.majorVersion);
            target.WriteByte(data.minorVersion);
            target.WriteByte(data.revisionVersion);
            target.WriteByte(data.buildVersion);
        }

        public void writeShort(ushort data) {
            target.WriteByte((byte)(data >> 8));
            target.WriteByte((byte)data);
        }

        public void writeByte(byte data) {
            target.WriteByte(data);
        }

        public void writeUnicodeString(string value) {
            for (int i = 0; i < value.Length; i++) {
                writeShort(value[i]);
            }
        }

        public void writeAnsiString(string value) {
            for (int i = 0; i < value.Length; i++) {
                writeByte((byte)value[i]);
            }
        }

        public void writeString(string value, bool isUnicode) {
            if (isUnicode) {
                writeUnicodeString(value);
            } else {
                writeAnsiString(value);
            }
        }

        public void writeMember(MemberBuilder member) {
            writeInt(member.id);
        }

        public void writeCheckpoint(Checkpoint location) {
            writeInt(location.id);
        }
    }

    /// <summary>
    /// 当被子类重写时，负责计算子成员的序号。
    /// </summary>
    /// <param name="context"></param>
    public virtual void generateID(WriteContext context) {
        // 普通成员没有子成员，不需要处理。
    }

    /// <summary>
    /// 将当前成员的数据写入到指定的对象中。
    /// </summary>
    /// <param name="context"></param>
    public virtual void write(WriteContext context) {

        // 存储当前的偏移，用于之后写入索引表。
        offset = (uint)context.target.Position;

        // 计算标记位。
        if (location != null) {
            attributes |= MemberAttributes.hasSourceLine;
        }
        int annotationCount = annotations.length;
        if (annotationCount > 0) {
            attributes |= MemberAttributes.hasAnnotations;
        }
        if (doc != null) {
            attributes |= MemberAttributes.hasDoc;
        }
        if (customAttributes != null) {
            attributes |= MemberAttributes.hasCustomAttributes;
        }
        bool nameIsUnicode = Util.isUnicode(name);
        if (nameIsUnicode) {
            attributes |= MemberAttributes.unicodeName;
        }
        uint nameOffset;
        if (name.Length <= (nameIsUnicode ? 1 : 3)) {
            nameOffset = 0;
        } else {
            nameOffset = context.getStringOffset(name);
            if (nameOffset > 0) {
                attributes |= MemberAttributes.linkedName;
            } else {
                Debug.Assert(name.Length <= byte.MaxValue);
                context.setStringOffset(name, (uint)context.target.Position + 8);// 跳过 属性和父成员。
            }
        }

        // 写入必写属性。
        context.writeInt((uint)attributes);
        context.writeMember(context.parentMember);

        if (nameOffset > 0) {
            context.writeInt(nameOffset);
        } else {
            context.writeByte((byte)name.Length);
            context.writeString(name, nameIsUnicode);
        }

        if (location != null) {
            context.writeCheckpoint(location);
        }

        // 写入注解。
        if (annotationCount > 0) {
            Debug.Assert(annotationCount <= byte.MaxValue);
            context.writeByte((byte)annotationCount);
            foreach (Annotation anno in annotations) {
                context.writeMember(anno.type);
                if (anno.data == null) {
                    context.writeInt(0);
                } else {
                    context.writeByteArrayList(anno.data);
                }
            }
        }

        // 写入文档。
        if (doc != null) {
            context.writeInt((uint)doc.Length);
            context.writeUnicodeString(doc);
        }

        // 写入自定义属性。
        if (customAttributes != null) {
            context.writeByteArrayList(customAttributes);
        }

    }

    /// <summary>
    /// 写入当前成员的索引表。
    /// </summary>
    /// <param name="context"></param>
    public virtual void writeIndex(WriteContext context) {
        // 普通成员没有子成员，不需要处理。
    }

    #endregion

}
